package com.woniuxy.microseckillserver.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.woniuxy.microcommonserver.bean.gy.GoodsInfo;
import com.woniuxy.microcommonserver.bean.order_caize.OrderInfo;
import com.woniuxy.microcommonserver.bean.seckill_lk.SeckillGoodsInfo;
import com.woniuxy.microcommonserver.bean.seckill_lk.SellRequest;
import com.woniuxy.microcommonserver.pageHelper.PageRequest;
import com.woniuxy.microseckillserver.mapper.SeckillMapper;
import com.woniuxy.microseckillserver.openFeign.OrderOpenFeign;
import com.woniuxy.microseckillserver.service.ISeckillService;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;

/**
 * @Author: 刘康
 * @Date: 2021/1/22 10:10
 * @Description:
 */
@Service
@Transactional(readOnly = true)
public class SeckillServiceImpl implements ISeckillService {

    @Resource
    private SeckillMapper seckillMapper;
    @Resource
    private HashOperations hashOperations;
    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private RabbitTemplate rabbitTemplate;
    @Resource
    private OrderOpenFeign orderOpenFeign;

    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    @Override
    public void saveSeckillGoods(SeckillGoodsInfo seckillGoodsInfo) {
        seckillMapper.saveSeckillGoods(seckillGoodsInfo);

        //redis中的商品信息
        //用日期作为key值，每日创建新key，每日清除过期(元素最后一个end_time)
        String hashKey = "seckillGoods"+new Date().getDate();
        hashOperations.put(hashKey,seckillGoodsInfo.getId().toString(),seckillGoodsInfo);
        //end_time距现在的时间大于过期时间，更新过期
        if ((seckillGoodsInfo.getEndTime().getTime() - new Date().getTime())/1000>redisTemplate.getExpire(hashKey)){
            //更新过期时间
            redisTemplate.expireAt(hashKey,seckillGoodsInfo.getEndTime());
        }

    }

    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    @Override
    public void updateSeckillGoods(SeckillGoodsInfo seckillGoodsInfo) {
        seckillMapper.updateSeckillGoods(seckillGoodsInfo);

        for (int i = new Date().getDate(); i >0; i--) {
            String hashKey = "seckillGoods"+i;
            SeckillGoodsInfo obj = (SeckillGoodsInfo)hashOperations.get(hashKey, seckillGoodsInfo.getId().toString());

            if (obj != null){
                GoodsInfo goodsInfo = obj.getGoodsInfo();

                seckillGoodsInfo.setGoodsInfo(goodsInfo);

                hashOperations.put("seckillGoods"+new Date().getDate(),seckillGoodsInfo.getId().toString(),seckillGoodsInfo);
                if ((seckillGoodsInfo.getEndTime().getTime() - new Date().getTime())/1000>redisTemplate.getExpire(hashKey)){
                    //更新过期时间
                    redisTemplate.expireAt(hashKey,seckillGoodsInfo.getEndTime());
                }
                return;
            }
        }

    }

    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    @Override
    public void deleteSeckillGoods(Long id) {
        SeckillGoodsInfo seckillGoodsInfo = new SeckillGoodsInfo();
        seckillGoodsInfo.setId(id);
        seckillGoodsInfo.setIsDelete(1);

        seckillMapper.updateSeckillGoods(seckillGoodsInfo);

        for (int i = new Date().getDate(); i >0 ; i--) {
            String hashKey = "seckillGoods"+i;
            if (hashOperations.get(hashKey, id.toString()) != null){
                hashOperations.delete(hashKey, id.toString());
                return;
            }
        }
    }

    @Override
    public PageInfo<SeckillGoodsInfo> findAllLimit(PageRequest pageRequest) {
        return PageHelper.startPage(pageRequest.getPageNum(),pageRequest.getLimit()).doSelectPageInfo(()->seckillMapper.findAll(pageRequest));
    }

    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    @Override
    public void order(SellRequest sellRequest) {

        //产生订单数据(订单模块openFeign实现)
        OrderInfo orderInfo = new OrderInfo();
        Long orderId = orderOpenFeign.saveOrder(orderInfo);
        sellRequest.setOrderId(orderId);

        //加个锁（杜绝超卖）
        RLock rlock = redissonClient.getLock("lock_"+sellRequest.getGoodsID());
        rlock.lock();//获得Redis分布式锁
        //先查询数据库中，是否真的还有库存
        SeckillGoodsInfo seckillGoodsInfo =  seckillMapper.getOneById(sellRequest.getGoodsID());
        if(seckillGoodsInfo.getStock() > 0){

            //减去库存
            seckillGoodsInfo.setStock(seckillGoodsInfo.getStock()-1);
            seckillMapper.updateSeckillGoods(seckillGoodsInfo);

            //等待用户支付(RabbitMQ 延迟队列)
            rabbitTemplate.convertAndSend("pay.exchange","pay.info.routing.key",
                    JSONObject.toJSONString(sellRequest));
        }
        rlock.unlock();//释放Redis分布式锁

    }


}
